﻿#region copyright
//<copyright>
// Copyright(C) 2012 TrackerRealm Corporation
// This file is part of the open source project - Jazz. http://jazz.codeplex.com
// 
// Jazz is open software: you can redistribute it and/or modify it 
// under the terms of the GNU Affero General Public License (AGPL) as published by 
// the Free Software Foundation, version 3 of the License.
// 
// Jazz is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty 
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
//  See the GNU Affero General Public License (AGPL) for more details.
// 
// You should have received a copy of the GNU General Public 
// License along with Jazz.  If not, see <http://www.gnu.org/licenses/>.
//
// REMOVAL OF THIS NOTICE IS VIOLATION OF THE COPYRIGHT. 
//</copyright>
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using TrackerRealm.Jazz.Common;
using C = TrackerRealm.Jazz.Common.JazzConstants;

namespace TrackerRealm.Jazz.Client
{
    /// <summary>
    /// 
    /// </summary>
    public struct jAclItem
    {
        #region FactoryMethods
        #region ReadOnly
        /// <summary>
        /// Creates an 'ReadOnly' Acl item for the specified 'role'.
        /// <para>When an 'ReadOnly' item is added to an ACL of a 'jObject', then
        /// read only access is granted to the object for users with that role.</para>
        /// <para>Note:  When an object is 'ReadOnly' then methods may not be executed. 
        /// The '<see cref="AccessorMethodAttribute"/>' can be used to allow designated methods to execute
        /// when the object is 'ReadOnly'.</para>
        /// </summary>
        /// <param name="role"></param>
        /// <returns></returns>
        public static jAclItem ReadOnly(jRoleBase role)
        {
            return new jAclItem(role, AccessControlType.ReadOnly);
        }
        /// <summary>
        /// Creates an 'ReadOnly' Acl item for the specified 'profile'.
        /// <para>When an 'ReadOnly' item is added to an ACL of a 'jObject', then
        /// read only access is granted to the object to a user logged in with the specified 'profile'.</para>
        /// <para>Note:  When an object is 'ReadOnly' then methods may not be executed. 
        /// The '<see cref="AccessorMethodAttribute"/>' can be used to allow designated methods to execute
        /// when the object is 'ReadOnly'.</para>
        /// </summary>
        /// <param name="profile"></param>
        /// <returns></returns>
        public static jAclItem ReadOnly(jProfileBase profile)
        {
            return new jAclItem(profile, AccessControlType.ReadOnly);
        }
        #endregion 
        #region CreateAccessible
        /// <summary>
        /// Creates an 'Accessible' Acl item for the specified 'role'.
        /// <para>When an 'Accessible' Acl item is added to an ACL of a 'jObject', then
        /// access is granted to the object for users with that role.</para>
        /// </summary>
        /// <param name="role"></param>
        /// <returns></returns>
        public static jAclItem Accessible(jRoleBase role)
        {
            return new jAclItem(role, AccessControlType.Accessible);
        }
        /// <summary>
        /// Creates an 'Accessible' Acl item for the specified 'profile'.
        /// <para>When an 'Accessible' Acl item is added to an ACL of a 'jObject', then
        /// access is granted to a user logged in with the specified 'profile'.</para>
        /// </summary>
        /// <param name="profile"></param>
        /// <returns></returns>
        public static jAclItem Accessible(jProfileBase profile)
        {
            return new jAclItem(profile, AccessControlType.Accessible);
        }
        #endregion
        #region CreateNotAccessible
        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="role"></param>
        ///// <returns></returns>
        //public jAclItem CreateNotAccessible(jRoleBase role)
        //{
        //    return new jAclItem(role, AccessControlType.NotAccessible);
        //}
        #endregion
        #endregion
        #region EmptyArray
        /// <summary>
        /// 
        /// </summary>
        public readonly static jAclItem[] EmptyArray = new jAclItem[0];
        #endregion
        //
        // Factory methods
        #region Create
        /// <summary>
        /// 
        /// </summary>
        /// <param name="roleOrProfile"></param>
        /// <param name="controlType"></param>
        /// <returns></returns>
        private  static jAclItem Create(IjRoleOrProfile roleOrProfile, AccessControlType controlType)
        {
            if (!(controlType == AccessControlType.ReadOnly || controlType == AccessControlType.Accessible))
                throw new ArgumentException("Only control type of Read only or Accessible are allowed");
            return new jAclItem(roleOrProfile, controlType);
        }
        #endregion
        #region constructor
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="roleOrProfile"></param>
        /// <param name="controlType"></param>
        private jAclItem(IjRoleOrProfile roleOrProfile, AccessControlType controlType)
        {
            this.role = roleOrProfile;
            this.control = controlType;
        }
        #endregion
        //
        // instance properties
        //
        #region Role
        private IjRoleOrProfile role;
        /// <summary>
        /// 
        /// </summary>
        public IjRoleOrProfile Role
        {
            get { return this.role; }
        }
        #endregion
        #region Control
        private AccessControlType control;
        /// <summary>
        /// 
        /// </summary>
        public AccessControlType Control
        {
            get { return this.control; }
        }
        #endregion
        /// <summary>
        /// 
        /// </summary>
        public bool IsNull
        {
            get { return (this.role == null); }
        }
        #region Equality and GetHashCode methods
        /// <summary>
        /// Overloaded Equality Operator (==) for "jAclItem".
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(jAclItem a, jAclItem b)
        {
            // need to compare 
            return CompareEverything(ref a, ref b);

        }
        /// <summary>
        /// Returns true if all fields are equal.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private static bool CompareEverything(ref jAclItem a, ref jAclItem b)
        {
            if (a.role != b.role) return false;
            if (a.control != b.control) return false;
            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return (this.role.GetHashCode()<< 16) | ((Int32)0Xffff &this.control.GetHashCode());
        }
        /// <summary>
        /// Overloaded Not Equality Operator (!=) for <see cref="jAclItem"/>.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(jAclItem a, jAclItem b)
        {

            return (!jAclItem.CompareEverything(ref a, ref b));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            if (!(obj is jAclItem)) return false;
            return (this == ((jAclItem)obj));
        }
        #endregion
    }
}
